package multi_threaded;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import GUI.GUI_MonteCarlo;
import Thread.MonteCarloThread;


public class MonteCarloMulti implements MonteCarloThread{
	@Override
	public double MonteCarloStandardOption ( String CallPutFlag, final double S,final double X, double T,double r, double b,double v, final int nSteps, final int nSimulations) throws InterruptedException, ExecutionException 
	{
		long temps=System.currentTimeMillis();
		
		final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0;
	    int pool = (int)(numberOfCores / (1 - blockingCoefficient));
		
		double dt;
		double Sum=0;
		final double Drift;
		final double vSqrdt;
		double MonteCarloStandardOption;
		final Random rand=new Random();int z=0;
		
		dt = T / nSteps;
		Drift = ((b - (v*v) )/ 2) * dt;
		vSqrdt = v * Math.sqrt(dt);
		
		if (CallPutFlag.equals("c"))
			z = 1;
		else if(CallPutFlag.equals("p"))
			z = -1;
		
		
		final int z1=z;
		final int nbSim=nSimulations/pool;
		ExecutorService executorService = Executors.newFixedThreadPool(pool);
		
		for(int k=0;k<pool;k++){
			Sum+=executorService.submit(new Callable<Double>()
					{
				        @Override
						public Double call() throws Exception {
				        	double St=0;double Sum2=0;
				        	for(int i = 0; i<nbSim;i++){
				        		St=S;
					        	for(int j = 0; j<nSteps;j++)
					        		St=St*(Math.exp(Drift + vSqrdt * rand.nextGaussian())); 
				        		
					        	Sum2=Sum2 + Math.max(z1 * (St - X), 0);
				        	}
				        	return Sum2;	
				        }
					}).get();
		}
		executorService.shutdownNow();
		MonteCarloStandardOption = Math.exp( (-r * T) * (Sum / nSimulations));
		temps=System.currentTimeMillis()-temps;
		System.out.print("Resultat : "+MonteCarloStandardOption+" in "+temps+" millisecond");
		return MonteCarloStandardOption;
	}
	public static void main(final String[] args) {
		try {
			MonteCarloMulti m=new MonteCarloMulti();
			GUI_MonteCarlo gui=new GUI_MonteCarlo("Multi-Threaded",m);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
